# -*- coding: utf-8 -*-
###################################################################################
#   
#    Copyright (C) 2019 RedTN 
# 
#此程序是自由软件：您可以根据自由软件基金会发布的GNU Affero通用公共许可证（许可证的第3版或（由您选择）任何更高版本）的条款重新分发和/或修改它。
#这个程序是分发的，希望它是有用的，但没有任何保证；甚至没有隐含的保证适销性或适合特定用途。有关详细信息，请参阅GNU Affero通用公共许可证。
#
#您应该已经收到GNU Affero通用公共许可证的副本以及此程序。如果没有，请参见<http://www.gnu.org/licenses/>。#
###################################################################################
from odoo import models, fields, api, SUPERUSER_ID
from odoo.exceptions import UserError, ValidationError
from datetime import date,datetime

import logging
_logger = logging.getLogger(__name__)

class HrAppraisalComb(models.Model):
    _inherit = 'hr.appraisal'
    _description = 'Appraisal combine'

    use_rule_on = fields.Boolean(string = "use the appraisal rule")
    rule_id = fields.Many2one("hr.appraisal.rule",string = "appraisal rule")
    rule_type = fields.Selection(related = "rule_id.rule_type",string = "appraisal rule type")
    sale_amount_ratio = fields.Integer(string = "ratio of sale amount ")
    sale_received_ratio = fields.Integer(string = "ratio of  received payments")
    task_deviation_ratio = fields.Integer(string = "ratio of  task deviation")
    task_work_hours_ratio = fields.Integer(string = "ratio of  work hours")
    result_id = fields.Many2one('hr.appraisal.results', string = "Result", ondelete="set null")
    start_date = fields.Date("From Date",required = True,default=fields.Date.to_string(date.today()))
    end_date = fields.Date("To Date",required = True,default=fields.Date.to_string(date.today()))

    @api.onchange("rule_type")
    def _onchange_sale_amount_ratio(self):
        self.ensure_one()
        if self.emp_id and self.rule_type:
            self.sale_amount_ratio=self.rule_id.sale_amount_ratio
            self.sale_received_ratio=self.rule_id.sale_received_ratio
            self.task_deviation_ratio=self.rule_id.task_deviation_ratio
            self.task_work_hours_ratio=self.rule_id.task_work_hours_ratio
    
    
    def action_done(self):
        """ This function will start compute the sale and task appraisal about comployee
            specified in the appraisal"""

        if self.hr_emp and self.emp_survey_id:
            self.ensure_one()
        if not self.result_id:
            result = self.env['hr.appraisal.results'].create(
                {'appraisal_id': self.ids[0]})
            self.result_id = result.id
        else:
            result = self.result_id
        super(HrAppraisalComb,self).action_done()
        self.result_id._compute_survey_score()
        if self.rule_type and self.rule_type in 'sale':
            self.result_id._compute_sale_score()
        if self.rule_type and self.rule_type in 'task':
            self.result_id._compute_task_score()

    @api.constrains('sale_amount_ratio','sale_amount_ratio')
    def _check_sale_amount_ratio(self):
        if self.sale_amount_ratio <0 or self.sale_amount_ratio>100:
            raise ValidationError("Fields sale_amount_ratio must be a number between 0 - 100")
        if self.sale_received_ratio <0 or self.sale_received_ratio>100:
            raise ValidationError("Fields sale_received_ratio must be a number between 0 - 100")
        if (self.sale_amount_ratio +  self.sale_received_ratio)>100:
            raise ValidationError("Fields Total ratio must less than 100")
    @api.constrains('sale_amount_ratio','sale_amount_ratio')
    def _check_task_deviation_ratio(self):
        if self.task_deviation_ratio <0 or self.task_deviation_ratio>100:
            raise ValidationError("Fields task_deviation_ratio must be a number between 0 - 100")
        if self.task_work_hours_ratio <0 or self.task_work_hours_ratio>100:
            raise ValidationError("Fields task_work_hours_ratio must be a number between 0 - 100")
        if (self.task_deviation_ratio +  self.task_work_hours_ratio)>100:
            raise ValidationError("Fields Total ratio must less than 100")
	
class SurveyResult(models.Model):
    """ Metadata for a set of one user's answers to a particular survey """

    _name = "hr.appraisal.results"
    _rec_name = 'date_create'
    _description = 'Appraisal Results'

    appraisal_id = fields.Many2one('hr.appraisal', string='Appraisal', required=True, readonly=True, ondelete='restrict')
    emp_id = fields.Many2one(related = "appraisal_id.emp_id")
    emp_name = fields.Char(related = "emp_id.name",string='employee name',store = True)
    date_create = fields.Datetime('Creation Date', default=fields.Datetime.now, required=True, readonly=True, copy=False)
    survey_score = fields.Float("Score for the survey", compute="_compute_survey_score", default=0.0,store='true')
    sale_score = fields.Float("Score for the sale", compute="_compute_sale_score", default=0.0,store='true')
    task_score = fields.Float("Score for the task", compute="_compute_task_score", default=0.0,store='true')
    state = fields.Selection([('draft', 'Draft'), ('confirm', 'Confirm')],string='Status', default='draft')
	
	
	
    
    def action_result_confirm(self):
        self.ensure_one()
        self.state = 'confirm'
        self._write_to_contract(self.appraisal_id.start_date,self.appraisal_id.end_date)

    def action_results_confirm(self):
        ids = self.env.context.get('active_ids')
        for res in self.browse(ids):
            res.state = 'confirm'
            res._write_to_contract(res.appraisal_id.start_date,res.appraisal_id.end_date)

    def action_result_draft(self):
        self.ensure_one()
        self.state = 'draft'

    
    def _compute_survey_score(self):
        self.ensure_one()
        survey_ratio = 1
        if self.appraisal_id.rule_type and self.appraisal_id.rule_type  in 'sale':
#            sale_amount_ratio=self.appraisal_id.rule_id.sale_amount_ratio
#            sale_received_ratio=self.appraisal_id.rule_id.sale_received_ratio
            sale_amount_ratio=self.appraisal_id.sale_amount_ratio
            sale_received_ratio=self.appraisal_id.sale_received_ratio
            survey_ratio = 1 - (sale_amount_ratio + sale_received_ratio)/100
        if  self.appraisal_id.rule_type and self.appraisal_id.rule_type in 'task':
            stask_deviation_ratio=self.appraisal_id.task_deviation_ratio
            stask_work_hours_ratio=self.appraisal_id.task_work_hours_ratio
            survey_ratio = 1 - (stask_deviation_ratio + stask_work_hours_ratio)/100
        rec = self.env['survey.user_input'].search(['&',('appraisal_id','=',self.appraisal_id.id),('state','=','done')])
        score = 0
        lenth = len(rec)
        if lenth > 0:
            for user_input in rec:
                score += user_input.appraisal_score
            #self.survey_score = score/lenth/100 * survey_ratio
            if score/lenth/100 > survey_ratio +0.2:
                raise UserError(_("The answers value are too larger!"))
            else:
                self.survey_score = score/lenth/100
        else:
            self.survey_score = survey_ratio
            
            
            
           
            
            
    @api.depends('appraisal_id.sale_amount_ratio','appraisal_id.sale_received_ratio')
    def _compute_sale_score(self):
        if self.appraisal_id.rule_type and self.appraisal_id.rule_type in 'sale':
            record = self.env['sale.order'].search([('user_id','=',self.emp_id.user_id.id),('state','=','done'),('date_order','>=',datetime.combine(self.appraisal_id.start_date, datetime.min.time())),('date_order','<=',datetime.combine(self.appraisal_id.end_date, datetime.max.time()))])
            order_total = sum(line.amount_total for line in record)

            record = self.env['account.payment'].search([('invoice_ids.user_id','=',self.emp_id.user_id.id),('state','=','posted'),('payment_date','>=',datetime.combine(self.appraisal_id.start_date, datetime.min.time())),('payment_date','<=',datetime.combine(self.appraisal_id.end_date, datetime.max.time()))])
            payment_total = sum(line.amount for line in record)

            amount_ratio = self.appraisal_id.sale_amount_ratio
            received_ratio = self.appraisal_id.sale_received_ratio

            rec = self.env['hr.appraisal.target'].search([('sale_person','=',self.emp_id.id)],limit = 1)
            sale_amount = rec.sale_amount
            sale_received = rec.sale_received
            self.sale_score = 0
            if sale_amount and amount_ratio:
                amount_rate=order_total*100/sale_amount
                rec = self.env['hr.appraisal.amount.line'].search([],order = 'floor DESC')
                for line in rec:
                    if line.floor >= amount_rate:
                        amount_rate = line.grade
                        break
                self.sale_score += amount_rate * amount_ratio/100.0
            else:
                raise UserError(_("sale target have not been set!"))
            
            if sale_received and received_ratio:
                received_rate=payment_total*100/sale_received
                rec = self.env['hr.appraisal.received.line'].search([],order = 'floor DESC')
                for line in rec:
                    if line.floor >= received_rate:
                        received_rate = line.grade
                        break
                self.sale_score += received_rate * received_ratio/100.0
            else:
                raise UserError(_("return target  have not been set!"))
            
    #        raise UserError("this is a test%d,amount %f,received %f " % (self.sale_score,order_total,payment_total))


    @api.depends('appraisal_id.task_deviation_ratio','appraisal_id.task_work_hours_ratio')
    def _compute_task_score(self):

        if self.appraisal_id.rule_type and self.appraisal_id.rule_type in 'task':
            deviation_ratio = self.appraisal_id.task_deviation_ratio
            work_hour_ratio = self.appraisal_id.task_work_hours_ratio

            dev_score = list()
            work_score = list()
            rec_dev = self.env['hr.appraisal.deviation.line'].search([],order = 'floor DESC')
            len1 = len(rec_dev)
            min_dev_grade = rec_dev[len1-1].grade if len1 >0 else 1
            rec_work = self.env['hr.appraisal.workhour.line'].search([],order = 'floor DESC')
            len2 = len(rec_work)
            min_work_grade = rec_work[len2-1].grade	if len2 >0	else 1
            self.task_score = 0
            task_ids =  self.env['project.task'].search([('user_id','=',self.emp_id.user_id.id),('date_end', '>=', self.appraisal_id.start_date),('date_end', '<=', self.appraisal_id.end_date)])
            for record in task_ids:
                level_rate = record.task_level
                dev = record.points
                work = record.total_hours_spent*100/record.planned_hours
                if len(rec_dev) and deviation_ratio:
                    dev_rate = 100
                    for line in rec_dev:
                        if line.floor >= dev:
                            dev_rate = line.grade
                            break
                    dev_score.append(dev_rate * level_rate)
                    
                if len(rec_dev) and work_hour_ratio:
                    work_rate = 100
                    for line in rec_work:
                        if line.floor >= work:
                            work_rate = line.grade
                            break
                    work_score.append(work_rate*level_rate)
            if len(dev_score):
                self.task_score += sum(dev_score)/len(dev_score) * deviation_ratio/100.0 
            else:
                self.task_score +=min_dev_grade* deviation_ratio/100.0 
            if len(work_score):
                self.task_score +=  sum(work_score)/len(work_score) * work_hour_ratio/100.0
            else:
                self.task_score +=min_work_grade* work_hour_ratio/100.0

    #        raise UserError('this is a tttt,dev_score %s, task_score:%s,task_score %f，mindev' % (dev_score,work_score,self.task_score))

    def _write_to_contract(self,date_from,date_to):
        
        
        # a contract is valid if it ends between the given dates
        clause_1 = ['&', ('date_end', '<=', date_to), ('date_end', '>=', date_from)]
        # OR if it starts between the given dates
        clause_2 = ['&', ('date_start', '<=', date_to), ('date_start', '>=', date_from)]
        # OR if it starts before the date_from and finish after the date_end (or never finish)
        clause_3 = ['&', ('date_start', '<=', date_from), '|', ('date_end', '=', False), ('date_end', '>=', date_to)]
        clause_final = [('employee_id', '=', self.emp_id.id), ('state', '=', 'open'), '|', '|'] + clause_1 + clause_2 + clause_3
        contract_id = self.env['hr.contract'].search(clause_final,limit = 1)
        if len(contract_id)>0:
            contract_id.survey_score=self.survey_score
            contract_id.sale_score=self.sale_score
            contract_id.task_score=self.task_score
        else:
            raise UserError(_("This employee must have a contract!"))

class ApprContract(models.Model):
    _inherit = 'hr.contract'

    survey_score = fields.Float("Score for the survey", default=1.0)
    sale_score = fields.Float("Score for the sale", default=0.0)
    task_score = fields.Float("Score for the task",default=0.0)
